home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 011 / ramham.arc / RAMHAM.ASM next >
Assembly Source File  |  1986-01-03  |  16KB  |  523 lines

  1. page    60,132
  2.  
  3. title    RAMHAM    Hammer the PE out of RAM by Clifford A McCullough
  4. subttl    Version    1.00 December 15, 1985
  5.  
  6. comment    *    RamHammer is intended to discover latent parity    errors.
  7.     This is    done by    cyclicly writing a pattern to memory and then checking
  8.     that the pattern remains.  The pattern is checked several times    before
  9.     a new pattern is written.  This    requires the RAM to maintain the
  10.     pattern    for a period of    time.  The pattern progresses through each
  11.     block so that each byte    is tested with all patterns and    each bit is
  12.     tested both high and low.
  13.  
  14.     RamHammer checks that it resides completely within the lowest 64K
  15.     of memory.  For    this reason the    system should be booted    with a minimum
  16.     of resident user programs (if any).  RamHammer will not    check this
  17.     first block of memory.    Some other method must be used to check    this
  18.     block if it is suspected.
  19.  
  20.     When RamHammer detects a memory    error, it sends    to the screen a
  21.     message    including the time, the    memory address,    and the    bit that
  22.     was found to be    in error.  The ports and data bytes it uses to disable
  23.     the NMI    and parity reporting mechanism is specific to the IBM PC and
  24.     may not    be correct for "compatible" machines.
  25.  *
  26.  
  27. .radix    16
  28.  
  29. ;***** Equates *********************************************************
  30.  
  31. check_no    equ    0FF        ;number    of check cycles
  32. begin_blk    equ    004        ;beginning block to be checked
  33. end_blk        equ    040        ;last block to be checked
  34. nmi_port    equ    0A0        ;NMI on    / off register
  35. nmi_on        equ    080        ;turn NMI on
  36. nmi_off        equ    000        ;turn NMI off
  37. port_b        equ    061        ;hardware port B
  38. port_c        equ    062        ;hardware port C
  39. par_err        equ    0C0        ;parity    error bits - either brd
  40. par_err_m    equ    080        ;parity    error bit for main brd
  41. par_err_e    equ    040        ;parity    error bit for exp brd
  42. clr_pe        equ    030        ;bits to clear parity error latches
  43. stack_size    equ    0100        ;minimum size of program stack
  44. cr        equ    0Dh        ;carriage return character
  45. lf        equ    0A        ;line feed character
  46. bel        equ    07        ;bell character
  47.  
  48. ;***** Main Program ****************************************************
  49.  
  50. code    segment
  51.     assume    cs:code, ds:code, es:code, ss:code
  52.     org    100            ;where all good    .COM programs go
  53.  
  54. ;----- Start:  make some checks    and set    up stuff -----------------------
  55.  
  56. start    proc    near
  57.  
  58. ;check the address of the end of the program
  59.     mov    dx,offset too_big_msg    ;get error message
  60.     mov    ax,cs            ;get program segment
  61.     cmp    ax,1000            ;check for 1st 64K
  62.     jge    bye_bye            ;/
  63.     mov    cl,4            ;convert from this seg to abs number
  64.     shl    ax,cl            ;/
  65.     add    ax,offset prog_end    ;add in    the length of the prog
  66.     jc    bye_bye            ;check program size
  67.     add    ax,stack_size        ;add in    the length of the stack
  68.     jc    bye_bye            ;check program size
  69.  
  70. ;find end of user memory and set up block enable flags
  71.     int    12            ;get memory size in K bytes
  72.     mov    dx,offset too_small_msg    ;get next error    message
  73.     cmp    ax,4            ;check if total    memory > 64K
  74.     jng    bye_bye            ;/
  75.     mov    cl,4            ;convert to base 16K
  76.     shr    ax,cl            ;/
  77.     sub    ax,4            ;skip 1st 4 blocks
  78.     mov    cx,ax            ;set up    block counter
  79.     cld                ;set direction to increment
  80.     mov    al,0FF            ;get the block enable flag
  81.     mov    di,offset en_flags + 4    ;point to enable flags after 1st 4
  82.     repz    stosb            ;set flag for each block existing
  83.  
  84. ;check for reduced hammering area
  85.     mov    al,00            ;get block disable flag
  86.     std                ;set direction to decrement
  87.     mov    cx,040d            ;get last block
  88.     sub    cx,end_blk        ;any work to do?
  89.     jle    lower            ;/
  90.     mov    di,offset en_flags +39d    ;point to enable flags
  91.     repz    stosb            ;reset flags
  92. lower:
  93.     cld                ;set direction to increment
  94.     mov    cx,begin_blk        ;get starting point
  95.     sub    cx,04            ;any work to do?
  96.     jle    safe_stack        ;/
  97.     mov    di,offset en_flags + 4    ;point to enable flags
  98.     repz    stosb            ;reset flags
  99.  
  100. ;load a    "safe" stack pointer
  101. safe_stack:
  102.     mov    ax,cs            ;get program segment
  103.     mov    cl,4            ;convert from seg to abs
  104.     shl    ax,cl            ;/
  105.     neg    ax            ;get difference    from 64K
  106.     mov    sp,ax            ;load safe stack pointer
  107.  
  108. ;turn off NMI -    parity error interrupt
  109.     mov    al,nmi_off        ;get off byte
  110.     out    nmi_port,al        ;turn off nmi
  111.  
  112. ;start hammering RAM
  113.     sub    dl,dl            ;start pattern at 0
  114.     jmp    control_loop
  115.  
  116. ;installation error - either too big system or too small memory.
  117. ;print message and exit.
  118. bye_bye:
  119.     mov    ah,9            ;print message
  120.     int    21            ;/
  121.     int    20            ;bye bye
  122.  
  123. too_big_msg    db    cr, lf
  124.         db    "Program is not contained in first 64K of memory."
  125.         db    cr, lf,    bel
  126.         db    "Reduce system overhead and try again."
  127.         db    cr, lf,    "$"
  128.  
  129. too_small_msg    db    cr, lf
  130.         db    "User memory is not more than 64K bytes."
  131.         db    cr, lf,    bel
  132.         db    "Nothing remains to be checked."
  133.         db    cr, lf,    "$"
  134.  
  135. en_flags    db    40d dup(0)    ;40 block enable flags (cleared)
  136. pattern        db    10110010b    ;par = e, B2
  137.         db    11011001b    ;par = o, D9
  138.         db    01101100b    ;par = e, 6C
  139.         db    10110110b    ;par = o, B6
  140.         db    01011011b    ;par = o, 5B
  141.         db    00101101b    ;par = e, 2D
  142.         db    10010110b    ;par = e, 96
  143.         db    11001011b    ;par = o, CB
  144.         db    01100101b    ;par = e, 65
  145. pat_length    equ    this byte - pattern - 1    ;length    of test    pattern    - 1
  146.  
  147. start    endp
  148.  
  149. ;----- Control Loop ----------------------------------------------------
  150.  
  151. control_loop    proc    near
  152. ;enter:    dl = pattern pointer
  153.  
  154. ;set up    pattern    pointer    to new value
  155.     dec    dl            ;start at different spot than last
  156.     jge    write_pattern        ;check for wrap-around
  157.     inc    loop_counter        ;count loops
  158.     mov    dx,loop_counter        ;update    printout
  159.     mov    si,offset loop_hex    ;load storage location
  160.     mov    bx,offset hex_tbl    ;point to hex to ascii xlat table
  161.     call    hex2ascii        ;convert
  162.     mov    dl,pat_length        ;reset the pattern pointer
  163.  
  164. write_pattern:
  165. ;find first enabled block
  166.     sub    bx,bx            ;start at beginning
  167.     call    find_next_block        ;find the first    enabled    block
  168.     jc    exit            ;no blocks enabled
  169.  
  170. ;pattern write
  171. blk_write:
  172.     call    pat_write        ;do the    writing
  173.     call    find_next_block        ;find the next enabled block
  174.     jnc    blk_write        ;a block was found
  175.  
  176. ;all enabled blocks written with pattern
  177.     mov    dh,check_no        ;load number of    times to check
  178. cycle:
  179.  
  180. ;find first enabled block
  181.     sub    bx,bx            ;start at beginning
  182.     call    find_next_block        ;find the first    enabled    block
  183.     jc    exit            ;should    not happen
  184.  
  185. ;pattern check
  186. blk_check:
  187.     call    pat_check        ;do the    checking
  188.     call    find_next_block        ;find the next enabled block
  189.     jnc    blk_check        ;a block was found
  190.  
  191. ;all enabled blocks checked and    disabled if faulty
  192.     call    pacifier        ;look busy
  193.     dec    dh            ;decrement check counter
  194.     jnz    cycle            ;check for more    checking
  195.     jmp    control_loop
  196.  
  197. ;no more blocks    enabled    for checking
  198. exit:
  199.     mov    dx,offset exit_msg    ;print exit message
  200.     mov    ah,9            ;/
  201.     int    21            ;/
  202.     int    20            ;bye bye
  203.  
  204. exit_msg    db    cr, lf
  205.         db    "All memory blocks checked have errors."
  206.         db    cr, lf,    bel
  207.         db    "Execution terminated."
  208.         db    cr, lf,    "$"
  209.  
  210. loop_counter    dw    0FFFF        ;over all loop counter
  211. loop_hex    db    "0000-"        ;ascii of loop counter
  212. pac_hex        db    "0000$"        ;ascii of pacifier
  213.  
  214. control_loop    endp
  215.  
  216. ;***** Subroutines *****************************************************
  217.  
  218. ;----- Pacifier    --------------------------------------------------------
  219.  
  220. pacifier    proc    near
  221. ;enter:    dh = check counter; dl = pattern pointer
  222. ;exit:    ax, cx,    bp, si = lost
  223.  
  224.     push    bx            ;save block number
  225.     mov    bp,dx            ;save counter and pointer
  226.  
  227. ;get current cursor position
  228.     mov    ah,3            ;read cursor position
  229.     sub    bh,bh            ;/  page number    = 0
  230.     int    10            ;/
  231.     push    dx            ;save current cursor position
  232.  
  233. ;set cursor position
  234.     mov    ah,2            ;set cursor position
  235.     mov    dh,0            ;/  row    = 1
  236.     mov    dl,69d            ;/  column = 70
  237.     int    10            ;/  page number    = 0
  238.  
  239. ;convert pacifier to ascii
  240.     mov    dx,bp            ;restore counter and pointer
  241.     mov    si,offset pac_hex    ;point to storage location
  242.     mov    bx,offset hex_tbl    ;point to translation table
  243.     call    hex2ascii        ;make conversion
  244.  
  245. ;print pacifier
  246.     mov    dx,offset loop_hex    ;get start of message
  247.     mov    ah,9            ;print message
  248.     int    21            ;/
  249.  
  250. ;restore stuff
  251.     mov    ah,2            ;restore cursor    position
  252.     sub    bh,bh            ;/  page number    = 0
  253.     pop    dx            ;/  get    old setting
  254.     int    10            ;/
  255.     mov    dx,bp            ;restore counter and pointer
  256.     pop    bx            ;restore block number
  257.     ret
  258.  
  259. pacifier    endp
  260.  
  261. ;----- find_next_block -------------------------------------------------
  262.  
  263. find_next_block    proc    near
  264. ;find the next enabled block after the one pointed to by bx and
  265. ;set up    es to point to the block of memory found
  266. ;enter:    bx = current block number
  267. ;exit:    bx = next block    number;     es = next block segment address
  268. ;    cx = lost; si =    lost
  269. ;    cy set = end of    blocks reached;    cy clear = next    block found
  270.  
  271.     mov    cx,length en_flags - 1    ;total number of blocks    - 1
  272.     sub    cx,bx            ;set count to remaining    blocks
  273.     jz    none_found        ;already at end    of blocks
  274. next_blk:
  275.     inc    bx            ;point to next block
  276.     cmp    byte ptr en_flags[bx],0FF    ;is it enabled?
  277.     je    found_blk        ;/  yes    - found    a good block
  278.     loop    next_blk        ;/  no    - check    next
  279. none_found:
  280.     stc                ;set end of blocks flag
  281.     ret
  282.  
  283. found_blk:
  284.     mov    si,bx            ;do not    disturb    bx
  285.     mov    cl,6            ;convert si to seg addr
  286.     ror    si,cl            ;/
  287.     mov    es,si            ;es points to 16K memory block
  288.     clc                ;set found block flag
  289.     ret
  290.  
  291. find_next_block    endp
  292.  
  293. ;----- pat_write -------------------------------------------------------
  294.  
  295. pat_write    proc    near
  296. ;do the    actual pattern writing
  297. ;enter:    dl = pattern start pointer; es = segment address to put    pattern    in
  298. ;exit:    ax, cx,    si, di = lost
  299.  
  300.     mov    cx,4000            ;set counter to    block size
  301.     sub    di,di            ;clear destination index
  302.     mov    al,dl            ;get pattern start pointer
  303.     cbw                ;clear high byte
  304.     add    ax,offset pattern    ;complete index    addr to    pattern
  305.     mov    si,ax            ;set source index
  306. write_next:
  307.     movsb                ;put pattern byte in block
  308.     cmp    si,offset pattern + pat_length    ;check source index
  309.     jle    skip2            ;if necessary ...
  310.     mov    si,offset pattern    ;/  reset pattern pointer
  311. skip2:
  312.     loop    write_next        ;write next byte
  313.     ret
  314.  
  315. pat_write    endp
  316.  
  317. ;----- pat_check -------------------------------------------------------
  318.  
  319. pat_check    proc    near
  320. ;do the    actual pattern checking
  321. ;enter:    dl = pattern start pointer; es = segment address of pattern
  322. ;    bx = current block number
  323. ;exit:    ax, cx,    si, di = lost
  324. ;    if error found:    control    is passed to bad_byte procedure
  325. ;        di = bad byte index + 1; si = pattern index + 1
  326.  
  327.     mov    cx,4000            ;set counter to    block size
  328.     sub    di,di            ;clear destination index
  329.     mov    al,dl            ;get pattern start pointer
  330.     cbw                ;clear high byte
  331.     add    ax,offset pattern    ;complete index    addr to    pattern
  332.     mov    si,ax            ;set source index
  333. check_next:
  334.     cmpsb                ;check pattern byte in block
  335.     jne    bad_byte        ;oops!
  336.     in    al,port_c        ;check for parity error
  337.     test    al,par_err        ;/
  338.     jnz    bad_byte        ;oops!
  339.     cmp    si,offset pattern + pat_length    ;check source index
  340.     jle    skip3            ;if necessary ...
  341.     mov    si,offset pattern    ;/  reset pattern pointer
  342. skip3:
  343.     loop    check_next        ;check next byte
  344.     ret
  345.  
  346. pat_check    endp
  347.  
  348. ;----- bad_byte    --------------------------------------------------------
  349.  
  350. bad_byte    proc    near
  351. ;a bad byte was    found in memory.  report it and    disable    the block
  352. ;enter:    bx = current block number; es =    current    block segment address
  353. ;    di = bad byte index + 1; si = pattern index + 1
  354. ;exit:    ax, cx,    si = lost
  355.  
  356.     push    dx            ;save pattern start pointer
  357.     mov    dx,offset crlf        ;print a new line
  358.     mov    ah,9            ;/
  359.     int    21            ;/
  360.  
  361. ;check for source of error
  362.     dec    di            ;correct for last increment
  363.     dec    si            ;/
  364.     cmp    si,offset pattern    ;check source index
  365.     jge    skip4            ;if necessary ...
  366.     mov    si,offset pattern + pat_length    ;/  reset pattern pointer
  367. skip4:
  368.     mov    al,es:[di]        ;get bad byte
  369.     xor    al,[si]            ;check for a bad bit
  370.     jnz    bit_error        ;/
  371.     in    al,port_c        ;get parity error bits
  372.     mov    dx,offset mpe_msg    ;get main pe message
  373.     test    al,par_err_m        ;check for main    brd parity error
  374.     jnz    err_recover        ;/
  375.     mov    dx,offset epe_msg    ;get expansion pe message
  376.     test    al,par_err_e        ;check for exp brd parity error
  377.     jnz    err_recover        ;/
  378.  
  379. ;error detected    by pat_check but the source was    not located.
  380. ;print message but do not disable this block.  it will be checked again.
  381.     mov    dx,offset shit_msg    ;print the message ...
  382.     jmp    short noerr_recover    ;/  do not disable the block
  383.  
  384. bit_error:
  385. ;a bit error was located.  separate the    bits and include in the    message.
  386.     mov    si,offset err_byte + 7    ;get storage location
  387.     mov    cx,8            ;get count
  388. store_bit:
  389.     mov    ah,018            ;get ascii "0" pre-shifted
  390.     shr    al,1            ;put bit in carry
  391.     rcl    ah,1            ;get bit from carry
  392.     mov    [si],ah            ;store ascii of    bit
  393.     dec    si            ;point to next bit
  394.     loop    store_bit        ;do all    bits
  395.     mov    dx,offset bit_msg    ;get bit error message
  396.  
  397. err_recover:
  398.     mov    byte ptr en_flags[bx],00    ;disable this block
  399. noerr_recover:
  400.     mov    ah,9            ;DOS print message function
  401.     int    21            ;/
  402.     call    get_time        ;get time and include in status_msg
  403.     push    bx            ;save block number
  404.     mov    bx,offset hex_tbl    ;point to hex to ascii xlat table
  405.     mov    dx,es            ;separate block    segment, convert
  406.     mov    si,offset err_blk    ;/  to ascii, and include in
  407.     call    hex2ascii        ;/  status_msg
  408.     mov    dx,di            ;separate memory address, convert
  409.     mov    si,offset err_addr    ;/  to ascii, and include in
  410.     call    hex2ascii        ;/  status_msg
  411.     mov    dx,offset status_msg    ;print status message
  412.     mov    ah,9            ;/
  413.     int    21            ;/
  414.     pop    bx            ;restore block number
  415.     pop    dx            ;restore pattern start pointer
  416.  
  417. ;clear parity error latches
  418.     in    al,port_b        ;get current status of port B
  419.     or    al,clr_pe        ;clear parity latches
  420.     out    port_b,al        ;/
  421.     xor    al,clr_pe        ;re-enable parity latches
  422.     out    port_b,al        ;/
  423.     ret
  424.  
  425. crlf        db    cr, lf,    "$"
  426. shit_msg    db    "An error was detected but not located.$"
  427. bit_msg        db    "The bit indicated was found to be in error: "
  428. err_byte    db    "00000000$"
  429. mpe_msg        db    "The main board parity bit was found to be in error.$"
  430. epe_msg        db    "The expansion board parity bit was found to be in "
  431.         db    "error.$"
  432. status_msg    db    cr, lf
  433.         db    "Time: "
  434. err_hour    db    "00:"
  435. err_min        db    "00   Memory Segment: "
  436. err_blk        db    "0000   Memory Address: "
  437. err_addr    db    "0000",    cr, lf,    "$"
  438.  
  439. bad_byte    endp
  440.  
  441. ;----- get_time    --------------------------------------------------------
  442.  
  443. get_time    proc    near
  444. ;get the time of day, make decimal, and    put it in status_msg.
  445. ;exit:    ax, cx = lost
  446.  
  447.     mov    ah,2C            ;DOS get time function
  448.     int    21            ;/
  449.     mov    al,ch            ;hours (0-23)
  450.     call    hex2dec            ;convert hex to    ascii decimal
  451.     mov    word ptr err_hour,ax    ;store ascii hours
  452.     mov    al,cl            ;minutes (0-59)
  453.     call    hex2dec            ;convert hex to    ascii decimal
  454.     mov    word ptr err_min,ax    ;store ascii minutes
  455.     ret
  456.  
  457. get_time    endp
  458.  
  459. ;----- hex2dec ---------------------------------------------------------
  460.  
  461. hex2dec        proc    near
  462. ;convert a hex number <100 in al into ascii decimal in ax.
  463. ;enter:    al = number to be converted
  464. ;exit:    ah = ones; al =    tens; ch = lost
  465.  
  466.     cbw                ;clear high byte
  467.     mov    ch,10d            ;divide    ax by 10
  468.     div    ch            ;/
  469.     add    ax,"00"            ;make ascii
  470.     ret
  471.  
  472. hex2dec        endp
  473.  
  474. ;----- hex2ascii -------------------------------------------------------
  475.  
  476. hex2ascii    proc    near
  477. ;convert a hex number in dx into ascii.     si points to storage location.
  478. ;enter:    dx = number to be converted; si    = storage location pointer
  479. ;    bx = offset of hex_tbl
  480. ;exit:    ah, cl = lost
  481.  
  482.     add    si,3            ;start at end of number
  483.     mov    ah,dl            ;do it to low byte
  484.     call    hex_lookup        ;/
  485.     mov    ah,dh            ;do it to high byte
  486.     call    hex_lookup        ;/
  487.     ret
  488.  
  489. hex2ascii    endp
  490.  
  491. ;----- hex_lookup ------------------------------------------------------
  492.  
  493. hex_lookup    proc    near
  494. ;separate two hex digits in ah,    convert    to ascii and store
  495. ;enter:    ah = two hex digits; si    = storage location
  496. ;    bx = hex_tbl offset
  497. ;exit:    al, cl = lost; si = decremented    by two
  498.  
  499.     mov    al,ah            ;get low byte
  500.     and    al,0F            ;get low nibble
  501.     xlat    hex_tbl            ;translate hex to ascii
  502.     mov    [si],al            ;store 1st/3rd digit
  503.     dec    si            ;point to next
  504.     mov    al,ah            ;get low byte again
  505.     mov    cl,4            ;set counter
  506.     shr    al,cl            ;shift high nibble to low nibble
  507.     xlat    hex_tbl            ;translate hex to ascii
  508.     mov    [si],al            ;store 2nd/4th digit
  509.     dec    si            ;point to next
  510.     ret
  511.  
  512. hex_tbl        db    "0123456789ABCDEF"    ;hex to    ascii conversion
  513.  
  514. hex_lookup    endp
  515.  
  516. ;***** Program End *****************************************************
  517.  
  518. prog_end    label    byte        ;label the end of the program
  519.  
  520. code    ends
  521.  
  522.     end    start
  523.